import org.junit.Test;
import static org.junit.Assert.*;
import java.util.HashSet;
import java.util.Set;

/**
 * Exercise2类的单元测试
 */
public class Exercise2Test {

    /**
     * 测试生成加法习题的方法
     * 验证：1. 生成指定数量的习题 2. 所有加法结果不超过100 3. 无重复习题
     */
    @Test
    public void testGenerateAdditionExercise() {
        Exercise2 exercise = new Exercise2();
        int count = 10; // 测试生成10道题
        exercise.generateAdditionExercise(count);
        
        // 验证生成的习题数量正确
        assertEquals("生成的加法习题数量不正确", count, exercise.size());
        
        // 验证所有加法结果不超过100
        for (BinaryOperation2 op : exercise) {
            assertTrue("加法结果超过100", op.getValue() <= 100);
            assertEquals("操作符不是加号", '+', op.getOperator());
        }
        
        // 验证无重复习题
        Set<String> uniqueExercises = new HashSet<>();
        for (BinaryOperation2 op : exercise) {
            assertTrue("存在重复的加法习题", uniqueExercises.add(op.toString()));
        }
    }

    /**
     * 测试生成减法习题的方法
     * 验证：1. 生成指定数量的习题 2. 所有减法结果非负且不超过100 3. 无重复习题
     */
    @Test
    public void testGenerateSubtractExercise() {
        Exercise2 exercise = new Exercise2();
        int count = 10;
        exercise.generateSubtractExercise(count);
        
        // 验证生成的习题数量正确
        assertEquals("生成的减法习题数量不正确", count, exercise.size());
        
        // 验证所有减法结果非负且不超过100
        for (BinaryOperation2 op : exercise) {
            assertTrue("减法结果为负数", op.getValue() >= 0);
            assertTrue("减法结果超过100", op.getValue() <= 100);
            assertEquals("操作符不是减号", '-', op.getOperator());
        }
        
        // 验证无重复习题
        Set<String> uniqueExercises = new HashSet<>();
        for (BinaryOperation2 op : exercise) {
            assertTrue("存在重复的减法习题", uniqueExercises.add(op.toString()));
        }
    }

    /**
     * 测试生成加减法混合习题的方法
     * 验证：1. 生成指定数量的习题 2. 包含加法和减法 3. 所有结果符合要求 4. 无重复习题
     */
    @Test
    public void testGenerateBinaryExercise() {
        Exercise2 exercise = new Exercise2();
        int count = 20; // 生成更多题以增加包含两种运算的概率
        exercise.generateBinaryExercise(count);
        
        // 验证生成的习题数量正确
        assertEquals("生成的混合习题数量不正确", count, exercise.size());
        
        boolean hasAddition = false;
        boolean hasSubtraction = false;
        Set<String> uniqueExercises = new HashSet<>();
        
        // 验证习题属性
        for (BinaryOperation2 op : exercise) {
            // 检查结果范围
            assertTrue("结果超过100", op.getValue() <= 100);
            
            // 检查是否包含加法和减法
            if (op.getOperator() == '+') {
                hasAddition = true;
            } else if (op.getOperator() == '-') {
                hasSubtraction = true;
                assertTrue("减法结果为负数", op.getValue() >= 0);
            }
            
            // 检查重复
            assertTrue("存在重复的混合习题", uniqueExercises.add(op.toString()));
        }
        
        // 验证至少包含一种加法和一种减法
        assertTrue("混合习题应至少包含一道加法题", hasAddition);
        assertTrue("混合习题应至少包含一道减法题", hasSubtraction);
    }

    /**
     * 测试contains方法
     * 验证能正确识别是否包含指定的习题
     */
    @Test
    public void testContains() {
        Exercise2 exercise = new Exercise2();
        // 生成一些习题
        AdditionOperation2 addOp = new AdditionOperation2(10, 20);
        SubtractOperation2 subOp = new SubtractOperation2(30, 15);
        
        // 添加到习题集
        exercise.add(addOp);
        exercise.add(subOp);
        
        // 测试包含的情况
        assertTrue("应该包含已添加的加法习题", exercise.contains(addOp));
        assertTrue("应该包含已添加的减法习题", exercise.contains(subOp));
        
        // 测试不包含的情况
        AdditionOperation2 anotherAddOp = new AdditionOperation2(15, 25);
        assertFalse("不应该包含未添加的习题", exercise.contains(anotherAddOp));
        
        // 测试非BinaryOperation2类型
        assertFalse("不应该包含非BinaryOperation2类型的对象", exercise.contains("不是习题的对象"));
    }

    /**
     * 测试当传入非法参数（负数或零）时，generateAdditionExercise方法应抛出异常
     */
    @Test(expected = IllegalArgumentException.class)
    public void testGenerateAdditionExerciseWithInvalidCount() {
        Exercise2 exercise = new Exercise2();
        exercise.generateAdditionExercise(-5); // 负数参数
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGenerateAdditionExerciseWithZeroCount() {
        Exercise2 exercise = new Exercise2();
        exercise.generateAdditionExercise(0); // 零参数
    }

    /**
     * 测试当传入非法参数时，generateSubtractExercise方法应抛出异常
     */
    @Test(expected = IllegalArgumentException.class)
    public void testGenerateSubtractExerciseWithInvalidCount() {
        Exercise2 exercise = new Exercise2();
        exercise.generateSubtractExercise(-10); // 负数参数
    }

    /**
     * 测试当传入非法参数时，generateBinaryExercise方法应抛出异常
     */
    @Test(expected = IllegalArgumentException.class)
    public void testGenerateBinaryExerciseWithInvalidCount() {
        Exercise2 exercise = new Exercise2();
        exercise.generateBinaryExercise(-3); // 负数参数
    }

    /**
     * 测试当传入非法参数时，formatAndDisplay方法应抛出异常
     */
    @Test(expected = IllegalArgumentException.class)
    public void testFormatAndDisplayWithInvalidColumns() {
        Exercise2 exercise = new Exercise2();
        exercise.generateAdditionExercise(5);
        exercise.formatAndDisplay(-2); // 非法列数
    }

    /**
     * 测试加法结果不超过100的约束
     */
    @Test
    public void testAdditionResultConstraint() {
        for (int i = 0; i < 100; i++) { // 测试多次以增加覆盖率
            AdditionOperation2 addOp = new AdditionOperation2();
            assertTrue("随机生成的加法结果应不超过100", addOp.getValue() <= 100);
        }
    }

    /**
     * 测试减法结果非负且不超过100的约束
     */
    @Test
    public void testSubtractionResultConstraint() {
        for (int i = 0; i < 100; i++) { // 测试多次以增加覆盖率
            SubtractOperation2 subOp = new SubtractOperation2();
            assertTrue("随机生成的减法结果应为非负数", subOp.getValue() >= 0);
            assertTrue("随机生成的减法结果应不超过100", subOp.getValue() <= 100);
        }
    }
}